#ifndef PUB_SUB_COMMON_H
#define PUB_SUB_COMMON_H

#include <fcntl.h>
#include <nanomsg/nn.h>
#include <nanomsg/pubsub.h>
#include <signal.h>
#include <sys/file.h>
#include <unistd.h>

#include <algorithm>
#include <chrono>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <random>
#include <stdexcept>
#include <string>
#include <thread>
#include <vector>
#include <sstream>

#include "libipc/ipc.h"

// URL for nanomsg communication
constexpr const char* URL = "ipc:///tmp/pub_sub_nanomsg.ipc";
// Number of messages to send/receive
constexpr int NUM_MESSAGES = 10000;
// Timeout for receiving messages
constexpr int RECEIVE_TIMEOUT = 5000;
// IPC route name
constexpr const char* kIpcRouteName = "pub_sub_nanomsg_shm";
// Minimum size of large data block (1 MB)
constexpr size_t kMinDataSize = 1024 * 1024;
// Maximum size of large data block (1 MB)
constexpr size_t kMaxDataSize = 1024 * 1024;
// Poll timeout in milliseconds
constexpr int POLL_TIMEOUT = 10;

///// for nanomsg ///////
// Buffer size
constexpr int BUFFER_SIZE = 16 * 1024 * 1024;
// Maximum receive size
constexpr int RECVMAXSIZE = 128 * 1024 * 1024;

// sleep for throttle messages
#ifndef THROTTLE_MESSAGE_SLEEP
#define THROTTLE_MESSAGE_SLEEP 100  // us
#endif

#ifndef ENABLE_CHANGE_BUFSIZE
#define ENABLE_CHANGE_BUFSIZE 1
#endif

// Debug flag
#ifndef DEBUG_ON
#define DEBUG_ON 0
#endif

// If enable crc check
#ifndef ENABLE_CRC_CHECK
#define ENABLE_CRC_CHECK 0
#endif

// Structure to hold large data blocks
struct LargeDataBlock {
  uint32_t length;
  uint16_t crc;
  std::vector<uint8_t> data;
};

// Function to calculate CRC-16 value
inline uint16_t calculate_crc(const std::vector<uint8_t>& data) {
  uint16_t crc = 0xFFFF;
  for (auto byte : data) {
    crc ^= byte;
    for (int i = 0; i < 8; ++i) {
      if ((crc & 0x0001U) != 0U) {
        crc = static_cast<uint16_t>((crc >> 1) ^ 0xA001U);
      } else {
        crc >>= 1;
      }
    }
  }
  return crc;
}

// Function to calculate CRC-16 value using char* pointer and length
inline uint16_t calculate_crc2(const char* data, size_t length) {
  uint16_t crc = 0xFFFF;

  for (size_t i = 0; i < length; ++i) {
    uint8_t byte = static_cast<uint8_t>(data[i]);  // Explicit cast to ensure correct operation

    crc ^= byte;
    for (int j = 0; j < 8; ++j) {
      if ((crc & 0x0001U) != 0U) {
        crc = static_cast<uint16_t>((crc >> 1) ^ 0xA001U);
      } else {
        crc >>= 1;
      }
    }
  }

  return crc;
}

// Function to create large data block filled with random data
inline uint32_t create_large_data(std::vector<uint8_t>& large_data) {
  std::random_device rd;
  std::mt19937 gen(rd());
  std::uniform_int_distribution<> dis(static_cast<int>(kMinDataSize), static_cast<int>(kMaxDataSize));

  size_t data_size = static_cast<size_t>(dis(gen));
  large_data.resize(data_size + sizeof(uint32_t) + sizeof(uint16_t));
  std::generate(large_data.begin() + sizeof(uint32_t) + sizeof(uint16_t), large_data.end(),
                [&]() { return gen() % 256; });
  return static_cast<uint32_t>(data_size);
}

// Forward declaration of the signal handler
void signal_handler(int signal);

// Function to set up signal handlers for graceful shutdown
inline void setup_signal_handlers() {
  signal(SIGINT, signal_handler);
  signal(SIGABRT, signal_handler);
  signal(SIGSEGV, signal_handler);
  signal(SIGTERM, signal_handler);
}

inline std::string get_currenttime_millis() {
  // 获取当前时间点
  auto now = std::chrono::system_clock::now();

  // 将时间点转换为时间戳（毫秒）
  auto duration_since_epoch = now.time_since_epoch();
  auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(duration_since_epoch).count();

  // 将时间戳转换为时间_t
  time_t t = std::chrono::system_clock::to_time_t(now);

  // 准备一个输出流用于构建时间字符串
  std::stringstream ss;
  ss << std::put_time(std::localtime(&t), "%Y-%m-%d %X.") << std::setfill('0') << std::setw(3) << (millis % 1000);

  // 返回构造好的时间字符串
  return ss.str();
}

class FileLock {
 public:
  FileLock() : fd_(-1), locked_(false) {
    const std::string path = "/tmp/pub_sub.lock";
    fd_ = open(path.c_str(), O_CREAT | O_RDWR, 0666);
    if (fd_ == -1) {
      throw std::runtime_error("Failed to open lock file");
    }
  }

  ~FileLock() {
    if (locked_) {
      unlock();
    }
    if (fd_ != -1) {
      close(fd_);
    }
  }

  void lock() {
    if (flock(fd_, LOCK_EX) == -1) {
      throw std::runtime_error("Failed to lock file");
    }
    locked_ = true;
  }

  void unlock() {
    if (flock(fd_, LOCK_UN) == -1) {
      throw std::runtime_error("Failed to unlock file");
    }
    locked_ = false;
  }

  bool check() {
    if (flock(fd_, LOCK_EX | LOCK_NB) == -1) {
      if (errno == EWOULDBLOCK) {
        return true;  // File is locked, indicating process 1 is ready
      }
      throw std::runtime_error("Failed to check lock file");
    }
    // If lock is acquired, release it immediately
    unlock();
    return false;  // File is not locked, indicating process 1 is not ready
  }

 private:
  int fd_;
  bool locked_;
};

#endif  // PUB_SUB_COMMON_H
